//
//  ViewController.m
//  GCD-Test
//
//  Created by lianglibao on 519/3/24.
//  Copyright © 519 lianglibao. All rights reserved.
//

#import "ViewController.h"
#import "UIView+ATFrame.h"

@interface ViewController ()
@property (nonatomic, strong) UIButton *btn1;
@property (nonatomic, strong) UIButton *btn2;
@property (nonatomic, strong) UIButton *btn3;
@property (nonatomic, strong) UIButton *btn4;
@property (nonatomic, strong) UITextView *logTextView;
@property (nonatomic, strong) dispatch_source_t processingQueueSource;
@property (nonatomic, strong) dispatch_queue_t queue;
@property (nonatomic, assign) BOOL running;
@property (nonatomic, strong) void(^block)(void);
@end

static NSInteger CYLTotalNumber = 100;
@implementation ViewController
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testPrintConslogToTextView];
    
//    __weak typeof(self) weakSelf = self;
//    void (^TestBlock)(void) = ^{
//        weakSelf.block = ^{
//            NSLog(@"%s", __func__);
//        };
//    };
//
//    TestBlock();
//    if (self.block) {
//        self.block();
//    }
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.logTextView.size = CGSizeMake(self.view.width, self.view.height - self.btn1.bottom - 20);
    self.logTextView.origin = CGPointMake(0, self.btn1.bottom+10);
}

/**
 判断App是否有设置代理(防止被抓包).
 * 注意:使用此方法一定要在info.plist里面设置App Transport Security Settings的Allow Arbitrary Loads为YES
 @return 返回是否被设置代理
 */
+ (BOOL)getProxyStatus {
    NSDictionary *proxySettings = (NSDictionary *)CFBridgingRelease(CFNetworkCopySystemProxySettings());
    NSArray *proxies = (NSArray *)CFBridgingRelease(CFNetworkCopyProxiesForURL((CFURLRef)CFBridgingRetain([NSURL URLWithString:@"http://www.google.com"]), (CFDictionaryRef)CFBridgingRetain(proxySettings)));
    NSDictionary *settings = [proxies objectAtIndex:0];

    NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFProxyHostNameKey]);
    NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
    NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFProxyTypeKey]);

    if ([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"]) {
        //没有设置代理
        return NO;
    } else {
        //设置代理了
        return YES;
    }
}

/**
 将当前即时log打印输出到UITextView里
 */
- (void)testPrintConslogToTextView {
    [self setupSubviews];
    // 可以不用注册STDOUT_FILENO类型 文件描述符 log输出通知.
    
    [self redirectSTD:STDERR_FILENO];
//    [self redirectSTD:STDOUT_FILENO];
}

- (void)setupSubviews {
    [self.view addSubview:({
        UIButton *btn = [[UIButton alloc] init];
        [btn setTitle:@"异步栅栏函数\n并发队列执行" forState:UIControlStateNormal];
        btn.titleLabel.font = [UIFont systemFontOfSize:12];
        btn.titleLabel.numberOfLines = 0;
        btn.backgroundColor = [UIColor lightGrayColor];
        [btn sizeToFit];
        CGPoint point = CGPointMake(20, 10);
        btn.origin = point;
        [btn addTarget:self
                    action:@selector(testGCDAsyncBarrierAsyncQueue)
          forControlEvents:UIControlEventTouchUpInside];
        self.btn1 = btn;
        btn;
    })];
    
    [self.view addSubview:({
        UIButton *btn = [[UIButton alloc] init];
        [btn setTitle:@"同步栅栏函数\n并发队列执行" forState:UIControlStateNormal];
        btn.titleLabel.font = [UIFont systemFontOfSize:12];
        btn.titleLabel.numberOfLines = 0;
        btn.backgroundColor = [UIColor lightGrayColor];
        [btn sizeToFit];
        CGPoint point = CGPointMake(self.btn1.right + 20, 10);
        btn.origin = point;
        [btn addTarget:self
                    action:@selector(testGCDsyncBarrierAsyncQueue)
          forControlEvents:UIControlEventTouchUpInside];
        self.btn2 = btn;
        btn;
    })];
    
    [self.view addSubview:({
        UIButton *btn = [[UIButton alloc] init];
        [btn setTitle:@"组队列实现方式一" forState:UIControlStateNormal];
        btn.titleLabel.font = [UIFont systemFontOfSize:12];
        btn.titleLabel.numberOfLines = 0;
        btn.backgroundColor = [UIColor lightGrayColor];
        [btn sizeToFit];
        btn.height = self.btn2.height;
        CGPoint point = CGPointMake(self.btn2.right + 20, 10);
        btn.origin = point;
        [btn addTarget:self
                action:@selector(testGCDGroup)
      forControlEvents:UIControlEventTouchUpInside];
        self.btn3 = btn;
        btn;
    })];
    
    [self.view addSubview:({
        UIButton *btn = [[UIButton alloc] init];
        [btn setTitle:@"组队列实现方式二" forState:UIControlStateNormal];
        btn.titleLabel.font = [UIFont systemFontOfSize:12];
        btn.titleLabel.numberOfLines = 0;
        btn.backgroundColor = [UIColor lightGrayColor];
        [btn sizeToFit];
        btn.height = self.btn3.height;
        CGPoint point = CGPointMake(self.btn3.right + 20, 10);
        btn.origin = point;
        [btn addTarget:self
                action:@selector(testGCDEnterLeaveGroup)
      forControlEvents:UIControlEventTouchUpInside];
        self.btn3 = btn;
        btn;
    })];
    
    [self.view addSubview:({
        UIButton *btn = [[UIButton alloc] init];
        [btn setTitle:@"演示GCD恢复和暂停" forState:UIControlStateNormal];
        btn.titleLabel.font = [UIFont systemFontOfSize:12];
        btn.titleLabel.numberOfLines = 0;
        btn.backgroundColor = [UIColor lightGrayColor];
        [btn sizeToFit];
        CGPoint point = CGPointMake(self.btn3.right + 20, 10);
        btn.origin = point;
        [btn addTarget:self
                    action:@selector(testDispatchResumeAndPause)
          forControlEvents:UIControlEventTouchUpInside];
        self.btn4 = btn;
        btn;
    })];

    [self.view addSubview:({
        UITextView *logTextView = [[UITextView alloc] init];
        self.logTextView = logTextView;
        logTextView.editable = NO;
        logTextView;
    })];
}


// 通知方法
- (void)redirectNotificationHandle:(NSNotification *)nf {
    // 设置在后台读取
    [[nf object] readInBackgroundAndNotify];
    NSData *data = [[nf userInfo] objectForKey:NSFileHandleNotificationDataItem];
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    // logTextView 就是要将日志输出的视图（UITextView）
    self.logTextView.text = [NSString stringWithFormat:@"%@\n\n%@",self.logTextView.text, str];
}

- (void)redirectSTD:(int)fd {
    // 初始化一个NSPipe 对象
    NSPipe * pipe = [NSPipe pipe] ;
    NSFileHandle *pipeReadHandle = [pipe fileHandleForReading];
    dup2([[pipe fileHandleForWriting] fileDescriptor], fd) ;
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(redirectNotificationHandle:)
                                                 name:NSFileHandleReadCompletionNotification
                                               object:pipeReadHandle]; // 注册通知
    [pipeReadHandle readInBackgroundAndNotify];
}

- (void)testGCDAsyncBarrierAsyncQueue {
    self.logTextView.text = nil;
    dispatch_queue_t concurrentQueue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
    
    /* 1.异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download1----%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download2----%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"---------------------%@------------------------\n\n%s\n",[NSThread currentThread], __func__);
    });
    
    /* 3. 异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download3----%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download4----%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    NSLog(@"---------------------end------------%@------------", [NSThread currentThread]);

}

- (void)testGCDsyncBarrierAsyncQueue {
    self.logTextView.text = nil;
    dispatch_queue_t concurrentQueue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
    
    /* 1.异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_barrier_sync(concurrentQueue, ^{
        NSLog(@"---------------------%@------------------------\n\n%s\n",[NSThread currentThread], __func__);
    });
    
    /* 3. 异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    NSLog(@"---------------------end------------%@------------", [NSThread currentThread]);

}


- (void)testGCDEnterLeaveGroup {
    self.logTextView.text = nil;
    /* 1. 创建队列 */
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    /* 2. 创建调度组 */
    dispatch_group_t group = dispatch_group_create();
    
    /* 3. 进入调度组, 这个函数后面的异步任务都进入调度组中 */
    
    /*dispatch_group_enter 和 dispatch_group_leave 是成对出现的 */
    dispatch_group_enter(group);
    
    dispatch_async(globalQueue, ^{
        NSLog(@"download1-------%@",[NSThread currentThread]);
        
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    
    dispatch_async(globalQueue, ^{
        NSLog(@"download2------%@",[NSThread currentThread]);
        
        dispatch_group_leave(group);
    });
    
    /* 这个函数本身是不阻塞的 */
    /* dispatch_group_notify 与 dispatch_group_enter(), dispatch_group_leave()实现组队列
     dispatch_group_notify拦截通知,当队列组中所有的任务都执行完毕的时候调用下面的函数
     dispatch_group_enter 和 dispatch_group_leave 是成对出现的,在任务执行前将任务加入组队列,在任务执行完后将将任务移出组队列
     dispatch_group_notify 非阻塞式
     0.dispatch_group_notify下方有主线程任务则先执行主线程任务
     1.再执行dispatch_group_notify之前的任务
     2.最后执行dispatch_group_notify之内的任务,任务执行线程取决于传入的队列类型
       01.传入的是主队列,则在主线程执行
       02.传入的是其他队列,则在子主线程执行
     */
    dispatch_group_notify(group, globalQueue, ^{
        NSLog(@"--------执行结束-------%@-----\n%s", [NSThread currentThread], __func__);
    });
    
    /* 这个函数本身是阻塞的 */
    /* dispatch_group_wait等待组队列任务执行完毕,当队列组中所有的任务都执行完毕的时候调用下面的函数
     dispatch_group_wait 阻塞式
     0.必须执行完dispatch_group_wait之前的任务
     1.再dispatch_group_wait之后的任务,哪怕是任务在主线程依然需要等待
     */
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"---------------------end------------%@------------", [NSThread currentThread]);
}


- (void)testGCDGroup {
    self.logTextView.text = nil;
    /* 1. 创建队列 */
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    /* 2. 创建调度组 */
    dispatch_group_t group = dispatch_group_create();
    
    /* 3. 封装任务并把任务添加到队列中
     参数1: 调度组
     参数2: 队列
     参数3: 封装任务
     */
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"1------%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"2------%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"3------%@",[NSThread currentThread]);
    });
    
    /* 4. 拦截通知, 当队列组中所有的任务都执行完毕的时候调用下面的函数 */
    /*
     dispatch_group_notify 任务在全局并发队列中执行
     dispatch_group_notify 非阻塞式
     0.dispatch_group_notify下方有主线程任务则先执行主线程任务
     1.再执行dispatch_group_notify之前的任务
     2.最后执行dispatch_group_notify之内的任务,任务执行线程取决于传入的队列类型
       01.传入的是主队列,则在主线程执行
       02.传入的是其他队列,则在子主线程执行
     */
    dispatch_group_notify(group, globalQueue, ^{
        NSLog(@"--------执行结束-------%@-----\n%s", [NSThread currentThread], __func__);
    });
    //    dispatch_group_notify(group, dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL), ^{
    //        NSLog(@"--------执行结束---%@-----", [NSThread currentThread]);
    //    });
    //    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //        NSLog(@"--------执行结束---%@-----", [NSThread currentThread]);
    //    });
    
    /* 4.1 dispatch_group_wait等待组队列任务,当队列组中所有的任务都执行完毕的时候调用下面的函数 */
    /*
     dispatch_group_wait 阻塞式
     0.必须执行完dispatch_group_wait之前的任务
     1.再dispatch_group_wait之后的任务,哪怕是任务在主线程依然需要等待
     */
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"---------------------end------------%@------------", [NSThread currentThread]);

}

- (void)tesGCDBarrier {
    /* 创建并发队列 */
    /* 栅栏函数不能使用全局并发队列, 必须是自己通过函数创建的并发队列 */
    
    dispatch_queue_t concurrentQueue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
    
    /* 1.异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    /* 2. 异步栅栏函数在并发队列执行 */
    /*
     能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_async非阻塞式;
     0.如果下方主线程有内容,先执行主线程任务
     1.等1,2完成后再执行栅栏任务
     2.等栅栏任务执行完后再执行栅栏后面的任务
     */
    //    dispatch_barrier_async(concurrentQueue, ^{
    //        for (NSUInteger i = 0; i < 5; i++) {
    //            NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //        }
    //    });
    
    
    
    
    /* 2. 异步栅栏函数在串行队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_async非阻塞式;
     0.如果下方主线程有内容,先执行主线程任务
     1.1,2,3,4任务与栅栏函数内任务交替执行
     2.不能达到栅栏作用
     */
    
    //    dispatch_barrier_async(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL), ^{
    //        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //    });
    
    
    /* 2. 异步栅栏函数在全局并发队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_async非阻塞式;
     0.如果下方主线程有内容,先执行主线程任务
     2.执行栅栏函数任务与1,2,3,4在子线程交替执行,不能达到栅栏作用
     */
    
//    dispatch_barrier_async(dispatch_get_global_queue(0, 0), ^{
//        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
//    });
    
    
    /* 2. 异步栅栏函数在主队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_async非阻塞式;
     0.如果下方主线程有内容,先执行主线程任务
     1.执行栅栏函数内主线程任务
     2.1,2,3,4交替执行不能达到栅栏作用
     */
    
    //    dispatch_barrier_async(dispatch_get_main_queue(), ^{
    //        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //    });
    
    //****************************************************************************************************
    
    /* 2. 同步栅栏函数在并发队列执行 */
    /*
     能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_sync阻塞式;
     0.先执行1,2任务
     1.再栅栏函数内任务
     2.如果下方主线程有内容,先执行主线程任务
     3.最后执行栅栏后面的异步任务
     */
    
//        dispatch_barrier_sync(concurrentQueue, ^{
//            NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
//        });
    
    /* 2. 同步栅栏函数在串行队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_sync阻塞式;
     0.执行栅栏函数内主线程任务
     1.如果下方主线程有内容,先执行主线程任务
     2.1,2,3,4交替执行不能达到栅栏作用
     */
    
    //    dispatch_barrier_sync(dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL), ^{
    //        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //    });
    
    /* 2. 同步栅栏函数在全局并发队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_sync阻塞式;
     0.执行栅栏函数任务并且在主线程执行
     1.如果下方主线程有内容,先执行主线程任务
     2.1,2,3,4交替执行不能达到栅栏作用
     */
    
    //    dispatch_barrier_sync(dispatch_get_global_queue(0, 0), ^{
    //        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //    });
    
    /* 2. 同步栅栏函数在主队列执行 */
    /*
     不能达到栅栏效果:先1,2 后3,4
     dispatch_barrier_sync阻塞式;
     死锁!! 导致程序崩溃.
     */
    
    //    dispatch_barrier_sync(dispatch_get_main_queue(), ^{
    //        NSLog(@"---------------------%@------------------------\n\n",[NSThread currentThread]);
    //    });
    
    
    
    
    /* 3. 异步函数 */
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(concurrentQueue, ^{
        for (NSUInteger i = 0; i < 5; i++) {
            NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    NSLog(@"---------------------end------------%@------------", [NSThread currentThread]);
}

- (void)otherTest {
    //    UIImage *image = [UIImage imageNamed:@"payment_info_level_bg"];
    //    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(10, 10, 0, 0));
    //    if (!imageRef) {
    //        NSLog(@"ImageRef is nil, originImageSize:%@ ,imageCutRect:%@", NSStringFromCGSize(image.size), NSStringFromCGRect(CGRectMake(10, 10, 5, 5)));
    //    }
    //
    //    UIImage *tileImage = [UIImage imageWithCGImage:imageRef];
    //    CGContextRef context = UIGraphicsGetCurrentContext();
    //    UIGraphicsPushContext(context);
    //    [tileImage drawInRect:CGRectMake(10, 10, 5, 5)];
    //    UIGraphicsPopContext();
    //    CGImageRelease(imageRef);
    //    NSLog(@"%@", tileImage);
    //    IOSurfaceRef surface;
    //    UICreateCGImageFromIOSurface(surface);

}


// MARK: - TEST Dispatch Task Resume and Pause
/**
 测试:GCD中任务暂停和恢复
 */
- (void)testDispatchResumeAndPause {
    if (self.processingQueueSource && self.running) {
        [self.btn4 setTitle:@"点击恢复GCD任务" forState:UIControlStateNormal];
        [self pause];
        return;
    } else if (self.processingQueueSource && !self.running) {
        [self.btn4 setTitle:@"点击暂停GCD任务" forState:UIControlStateNormal];
        [self resume];
        return;
    }
    [self.btn4 setTitle:@"点击暂停GCD任务" forState:UIControlStateNormal];
    
	//1.
	// 指定DISPATCH_SOURCE_TYPE_DATA_ADD，做成Dispatch Source(分派源)。设定Main Dispatch Queue 为追加处理的Dispatch Queue
//	_processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
//													dispatch_get_main_queue());
    _processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
                                                    dispatch_get_global_queue(0, 0));
	__block NSUInteger totalComplete = 0;
	dispatch_source_set_event_handler(_processingQueueSource, ^{
		//当处理事件被最终执行时，计算后的数据可以通过dispatch_source_get_data来获取。这个数据的值在每次响应事件执行后会被重置，所以totalComplete的值是最终累积的值。
        NSUInteger value = dispatch_source_get_data(self->_processingQueueSource);
		totalComplete += value;
		NSLog(@"进度：%@, 线程:%@", @((CGFloat)totalComplete/CYLTotalNumber), [NSThread currentThread]);
	});
	//分派源创建时默认处于暂停状态，在分派源分派处理程序之前必须先恢复。
	[self resume];
	
	
	//2.
	//恢复源后，就可以通过dispatch_source_merge_data向Dispatch Source(分派源)发送事件:
	//为了便于观察，将_queue做成“串行队列”
    //其实任务已经分发给队列_queue了,通过控制_queue来完成任务的开始与暂停
	_queue = dispatch_queue_create("com.ioschengxuyuan.queue1", 0);
	NSLog(@"🔴类名与方法名：%s（在第%d行），描述：%@", __PRETTY_FUNCTION__, __LINE__, @"启动队列");
	for (NSUInteger index = 0; index < CYLTotalNumber; index++) {
		dispatch_async(_queue, ^{
			if (!self.running) {
				return;
			}
            NSLog(@"🔴线程:%@", [NSThread currentThread]);
            dispatch_source_merge_data(self->_processingQueueSource, 1);
			usleep(200000);//0.2秒
		});
        NSLog(@" 🔴 分派源遍历计数:%lu 🔴", index);
	}
}

- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning];
	[self changeStatus:self.running];
}

- (void)changeStatus:(BOOL)shouldPause {
	if (shouldPause) {
		[self pause];
	} else {
		[self resume];
	}
}

- (void)resume {
	if (self.running) {
		return;
	}
	NSLog(@"✅恢复Dispatch Source(分派源)以及_queue");
	self.running = YES;
	dispatch_resume(_processingQueueSource);
	if (_queue) {
		dispatch_resume(_queue);
	}
}

- (void)pause {
	if (!self.running) {
		return;
	}
	NSLog(@"🚫暂停Dispatch Source(分派源)以及_queue");
	self.running = NO;
	dispatch_suspend(_processingQueueSource);
	dispatch_suspend(_queue);
}

/**
 测试:GCD中线程死锁状况.
 */
- (void)testGCDdeathLock {
    // 使用sync函数在当前串行队列执行任务
//    dispatch_queue_t serialQueue = dispatch_queue_create("com.GCD-Test.demo", DISPATCH_QUEUE_SERIAL);
//    dispatch_async(serialQueue, ^{
//        NSLog(@"================%s=====1=====%@", __func__, [NSThread currentThread]);
        // 1.当前是子线程串行队列,然后又往当前串行队列中添加同步任务.
//        dispatch_sync(serialQueue, ^{
//            NSLog(@"--------------%s", __func__);
//        });
        
        // 当前是子线程串行队列,然后往主队列中添加同步任务--->不会死锁.
//        dispatch_sync(dispatch_get_main_queue(), ^{
//            NSLog(@"--------------%s----2----%@", __func__, [NSThread currentThread]);
//        });
//
//        NSLog(@"+++++++++++%s+++++2+++++%@", __func__, [NSThread currentThread]);
//    });
    
    // 2.当前是主线程串行队列,然后往主队列中添加同步任务.
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"--------------%s----2----%@", __func__, [NSThread currentThread]);
    });

}


/**
 测试:当前在主线程,异步主队列回主线程执行任务效果.
 */
- (void)testAsyncMainQueueBlock {
    [self asyncMainBlock:^{
        NSLog(@"--------------%s--------%@", __func__, [NSThread currentThread]);
    }];
    
    NSLog(@"--------------end--------");
}

- (void)asyncMainBlock:(dispatch_block_t) block {
    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}


/**
 测试:dispatch_queue_set_specific来标记&获取当前队列
     只有任务处在标记specific队列中才能获取到specific队列
 */
- (void)testSpecificQueue {
    static void *queueKey1 = "queueKey1";
    
    dispatch_queue_t queue1 = dispatch_queue_create(queueKey1, DISPATCH_QUEUE_SERIAL);
    dispatch_queue_set_specific(queue1, queueKey1, &queueKey1, NULL);
    
    NSLog(@"1. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
    
    if (dispatch_get_specific(queueKey1)) {
        // 当前队列是主队列，不是queue1队列，所以取不到queueKey1对应的值，故而不执行
        NSLog(@"2. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
        [NSThread sleepForTimeInterval:1];
    } else {
        NSLog(@"3. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
        [NSThread sleepForTimeInterval:1];
    }
    
    dispatch_sync(queue1, ^{
        NSLog(@"4. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
        [NSThread sleepForTimeInterval:1];
        
        if (dispatch_get_specific(queueKey1)) {
            //当前队列是queue1队列，所以能取到queueKey1对应的值，故而执行
            NSLog(@"5. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
            [NSThread sleepForTimeInterval:1];
        }else{
            NSLog(@"6. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
            [NSThread sleepForTimeInterval:1];
        }
    });
    dispatch_async(queue1, ^{
        NSLog(@"7. t当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());
        [NSThread sleepForTimeInterval:1];
    });
    
    [NSThread sleepForTimeInterval:5];
}

@end
